package com.travel.service.impl;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.travel.context.UserContext;
import com.travel.exception.BusinessException;
import com.travel.mapper.TravelOrderInfoMapper;
import com.travel.dto.QrCodeDto;
import com.travel.pojo.Member;
import com.travel.pojo.TravelOrderInfo;
import com.travel.pojo.TravelProducts;
import com.travel.service.TicketRegistrationService;
import com.travel.vo.OrderVO;
import com.travel.pojo.TravelRegistration;
import com.travel.result.PageResult;
import com.travel.service.IMemberService;
import com.travel.service.TravelOrderInfoService;
import com.travel.service.TravelProductService;
import com.travel.vo.ContractInfoVo;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

/**
 * @author: libin
 * Date: 2025/6/10 16:09
 * Description:
 **/
@Service
public class TravelOrderInfoServiceImpl extends ServiceImpl<TravelOrderInfoMapper, TravelOrderInfo> implements TravelOrderInfoService {

    @Autowired
    private TravelProductService travelProductService;
    @Autowired
    private QrCodeService qrCodeService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private TravelOrderInfoMapper travelOrderInfoMapper;

    @Autowired
    private IMemberService memberService;

    @SneakyThrows
    @Override
    public OrderVO createOrderInfo(Integer productId, Integer userId)  {
        TravelProducts travelProduct = travelProductService.getById(productId);
        if (ObjectUtil.isEmpty(travelProduct)){
            throw new BusinessException("旅游基础数据不存在");
        }

        TravelOrderInfo travelOrderInfo = new TravelOrderInfo();
        travelOrderInfo.setProductId(productId);
        travelOrderInfo.setUserId(userId);
        travelOrderInfo.setOrderNo(generateOrderNo());
        travelOrderInfo.setAdultPrice(travelProduct.getAdultPrice());
        travelOrderInfo.setChildPrice(travelProduct.getChildPrice());
        travelOrderInfo.setStatus(0); // 代付款
        travelOrderInfo.setCreateTime(LocalDateTime.now());

        boolean save = save(travelOrderInfo);
        if (!save){
            throw new BusinessException("订单创建失败");
        }
        OrderVO orderVO = BeanUtil.copyProperties(travelOrderInfo, OrderVO.class);
        orderVO.setStatusText(getStatusText(travelOrderInfo.getStatus()));
        orderVO.setProductName(travelProduct.getName());

        // 生成二维码
        String orderInfo = "{\"orderNo\":\"" + orderVO.getOrderNo() +
                "\",\"status\":\"" + orderVO.getStatus() + "\"}";
        String codeToBase64 = qrCodeService.createCodeToBase64(orderInfo);
        // 存入redis缓存
        stringRedisTemplate.opsForValue().set("order:" + orderVO.getOrderNo(), codeToBase64);
        orderVO.setQrCodeBase64(codeToBase64);

        return orderVO;
    }

    private static String getStatusText(Integer status) {
        return switch (status) {
            case 0 -> "待付款";
            case 1 -> "待出行";
            case 2 -> "已完成";
            default -> "未知";
        };
    }


    // 生成订单号示例
    private String generateOrderNo() {
        return System.currentTimeMillis() + String.valueOf(new Random().nextInt(1000));
    }


    @Override
    public void updateStatusByQrCode(QrCodeDto qrCodeData) {
        // 1. 校验二维码信息合法性（订单号存在性、状态有效性等）
        LambdaQueryWrapper<TravelOrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TravelOrderInfo::getOrderNo, qrCodeData.getTicketId());
        TravelOrderInfo travelOrderInfo = getOne(queryWrapper);
        if (ObjectUtil.isEmpty(travelOrderInfo)){
            throw new BusinessException("订单不存在");
        }

        // 2. 仅当订单为"待支付"时可更新为"已支付"
        if (!"待支付".equals(qrCodeData.getStatus())) {
            throw new BusinessException("订单状态异常");
        }

        // 3. 更新订单状态
        LambdaUpdateWrapper<TravelOrderInfo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(TravelOrderInfo::getStatus, "已支付");
        updateWrapper.eq(TravelOrderInfo::getOrderNo, qrCodeData.getTicketId());
        boolean success = update(updateWrapper);
        if (!success){
            throw new BusinessException("更新失败");
        }
    }



    @Autowired
    private TicketRegistrationService ticketRegistrationService;

    @Override
    public ContractInfoVo getContractInfo(Integer orderId) {

        //1. 订单信息
        TravelRegistration registration = ticketRegistrationService.getById(orderId);


        if (ObjectUtil.isEmpty(registration)){
            throw new BusinessException("订单不存在");
        }

        // 2.订单对应的产品信息
        TravelProducts productInfo = travelProductService.getById(registration.getProductId());
        if (ObjectUtil.isEmpty(productInfo)){
            throw new BusinessException("产品不存在");
        }

        // 3.用户信息
        Member memberInfo = memberService.getById(registration.getUserId());
        if (ObjectUtil.isEmpty(memberInfo)){
            throw new BusinessException("用户不存在");
        }
        // 4.构建合同信息VO
        ContractInfoVo contractInfoVo = BeanUtil.copyProperties(registration, ContractInfoVo.class);
        // 用户信息
        contractInfoVo.setUsername(memberInfo.getName());
        contractInfoVo.setPhone(memberInfo.getPhone());

        // 产品信息
        contractInfoVo.setProductName(productInfo.getName());
        contractInfoVo.setImageUrl(productInfo.getImageUrl());
        contractInfoVo.setDescription(productInfo.getDescription());
        contractInfoVo.setLocation(productInfo.getLocation());
        contractInfoVo.setAdultPrice(productInfo.getAdultPrice());
        contractInfoVo.setChildPrice(productInfo.getChildPrice());
        return contractInfoVo;
    }


}
